package com.coder4j.starter.generator.service;

import com.alibaba.fastjson.JSON;
import com.coder4j.starter.generator.mapper.GeneratorMapper;
import com.coder4j.starter.mybatis.BaseEntityEnums;
import com.coder4j.starter.generator.vo.ColumnInfo;
import com.coder4j.starter.generator.vo.IndexInfo;
import com.coder4j.starter.generator.vo.TableColumnInfo;
import com.coder4j.starter.generator.vo.TableParams;
import com.coder4j.starter.generator.vo.TemplateEntity;
import com.coder4j.starter.tools.util.Mysql2JavaTypeCaster;
import com.coder4j.starter.tools.util.StringUtils;
import com.coder4j.starter.tools.vo.BaseException;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.FileResourceLoader;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.*;

/**
 * 核心逻辑
 *
 * @author Keller
 * @date 2020-11-13 17:48:16
 */
@Service
public class GeneratorService {


    /**
     * 文件分隔符，用于匹配不同文件系统（主要是Windows和MacOS、Linux）的差异
     */
    public static String separator = File.separator;

    /**
     * mapper，用于执行数据库操作，获取表结构信息
     */
    @Resource
    private GeneratorMapper mapper;

    /**
     * 根据表结构和配置信息，初始化模板
     *
     * @return
     */
    public List<TemplateEntity> initTemplate(TableParams params) {

        if (params == null
                || StringUtils.isEmpty(params.getTemplatePath())
                || params.getTableNames() == null
                || params.getTableNames().length < 1) {
            throw BaseException.error("缺少模板路径或表名");
        }

        List<TemplateEntity> entityList = new ArrayList<>();
        for (String item : params.getTableNames()) {

            if (StringUtils.isEmpty(item)) {
                continue;
            }
            String tableName;
            String entityName;
            if (item.contains(":")) {
                String[] array = item.split(":");
                tableName = array[0];
                entityName = array[1];
            } else {
                tableName = item;
                entityName = StringUtils.lineToHump(tableName);
            }
            entityName = StringUtils.firstToUpper(entityName);
            TemplateEntity entity = new TemplateEntity();
            entity.setTemplatePath(params.getTemplatePath());
            entity.setJavaPath(params.getJavaPath());
            entity.setVuePath(params.getVuePath());
            entity.setEntityName(entityName);
            entity.setInstanceName(StringUtils.firstToLower(entityName));
            entity.setTableName(tableName);
            entity.setTableComment(this.getTableComment(tableName));
            entity.setAuthor(params.getAuthor());

            //读取配置文件中设置的路径
            String javaPath = params.getJavaPath();
            //从路径中解析出包名
            String packageName = javaPath.substring(javaPath.indexOf("java" + separator) + 5).replace(separator, ".");
            entity.setPackageName(packageName);
            //根据数据库配置信息读取指定的数据表结构
            List<TableColumnInfo> tableInfoList = this.getColumnList(entity.getTableName());

            //设置数据表解析信息
            for (TableColumnInfo tableInfo : tableInfoList) {
                if (tableInfo.isKey()) {
                    //设置主键
                    entity.setKeyField(tableInfo);
                }
            }
            //设置字段列表
            entity.setList(tableInfoList);

            entityList.add(entity);
        }
        return entityList;
    }

    public void createJavaAndVue(TableParams params) {
        List<TemplateEntity> list = initTemplate(params);
        if (list == null || list.isEmpty()) {
            throw BaseException.error("initTemplate 失败，没有有效对象");
        }
        for (TemplateEntity template : list) {
            if (StringUtils.notEmpty(template.getJavaPath())) {
                //查询
                doCreate(template, separator + "vo",
                        template.getEntityName() + "Query.java", "BaseSoftDeleteQuery.txt", true);
                //展示
                doCreate(template, separator + "vo",
                        template.getEntityName() + "VO.java", "VO.txt", true);
                //导出
                doCreate(template, separator + "vo",
                        template.getEntityName() + "EO.java", "EO.txt", true);
                //Mapper
                doCreate(template, separator + "mapper",
                        template.getEntityName() + "Mapper.java", "BaseSoftDeleteMapper.txt", true);
                //IService
                doCreate(template, separator + "service",
                         template.getEntityName() + "Service.java", "ServiceImpl.txt", true);
                //ServiceImpl
//                doCreate(template, separator + "service" + separator + "impl",
//                        template.getEntityName() + "ServiceImpl.java", "ServiceImpl.txt", true);
                //Controller
                doCreate(template, separator + "controller",
                        template.getEntityName() + "Controller.java", "Controller.txt", true);
                //Entity
                createPOExtendsBaseEntity(template);
            }

            if (StringUtils.notEmpty(template.getVuePath())) {

                doCreate(template, separator + "views" + separator + template.getInstanceName(),
                        "page.js", "VuePage.txt", false);
                doCreate(template, separator + "views" + separator + template.getInstanceName(),
                        "index.vue", "VueIndex.txt", false);
                doCreate(template, separator + "views" + separator + template.getInstanceName(),
                        "form.vue", "VueForm.txt", false);
                doCreate(template, separator + "api" + separator,
                        template.getEntityName() + "Api.js", "VueApi.txt", false);
            }
        }
    }

    /**
     * 创建实体类
     *
     * @param template
     */
    private void createPO(final TemplateEntity template) {
        doCreate(template, separator + "entity",
                template.getEntityName() + "Entity.java", "Entity.txt", true);
    }

    private void createPOExtendsBaseEntity(final TemplateEntity template) {
        //取出 BaseEntity包含的字段
        Set<String> baseSet = new HashSet<>();
        for (BaseEntityEnums item : BaseEntityEnums.values()) {
            baseSet.add(item.name());
        }

        boolean isSoftDelete = false;
        List<TableColumnInfo> list = new ArrayList<>();
        TemplateEntity temp = JSON.parseObject(JSON.toJSONString(template), TemplateEntity.class);

        //过滤BaseEntity包含的字段
        for (TableColumnInfo item : template.getList()) {
            String javaName = item.getJavaName();
            if (!baseSet.contains(javaName)) {
                list.add(item);
            }
            if (BaseEntityEnums.isDeleted.name().equals(javaName)) {
                isSoftDelete = true;
            }
        }
        temp.setList(list);

        if (isSoftDelete) {
            doCreate(temp, separator + "entity",
                    template.getEntityName() + "Entity.java", "BaseSoftDeleteEntity.txt", true);
        } else {
            doCreate(temp, separator + "entity",
                    template.getEntityName() + "Entity.java", "BaseEntity.txt", true);
        }
    }

    /**
     * 执行创建方法
     *
     * @param template     模板对象
     * @param pathSuffix   类文件存放路径
     * @param templateName 模板文件名
     */
    private void doCreate(TemplateEntity template, String pathSuffix, String fileName, String templateName, boolean isJava) {
        String filePath = isJava ? template.getJavaPath() + pathSuffix : template.getVuePath() + pathSuffix;
        template.setTemplateName(templateName);
        createFile(template, filePath, fileName);
    }

    private void createFile(TemplateEntity template, String filePath, String fileName) {
        try {
            //指定模板路径
            String root = template.getTemplatePath() + File.separator;

            FileResourceLoader resourceLoader = new FileResourceLoader(root, "utf-8");

            Configuration cfg = Configuration.defaultConfiguration();
            GroupTemplate gt = new GroupTemplate(resourceLoader, cfg);
            //指定要加载的模板
            Template t = gt.getTemplate(template.getTemplateName());
            //绑定全局变量
            t.binding("template", template);
            //读取模板输出的文本
            String str = t.render();
            System.out.println(str);
            File dir = new File(filePath + File.separator);
            if (!dir.exists() && !dir.isDirectory()) {
                dir.mkdirs();
            }
            File file = new File(dir + File.separator + fileName);
            if (!file.exists()) {
                file.createNewFile();
            }
            FileWriter fileWriter = new FileWriter(file);
            BufferedWriter bw = new BufferedWriter(fileWriter);
            bw.write(str);
            bw.flush();
            bw.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

    private String getTableComment(String tableName) {
        List<String> list = mapper.baseQueryTableComment(tableName);
        if (list == null || list.isEmpty()) {
            return "";
        }
        return list.get(0);
    }

    /**
     * 获取表中的字段列表
     *
     * @param tableName
     * @return
     */
    private List<TableColumnInfo> getColumnList(String tableName) {
        List<ColumnInfo> columnList = mapper.baseQueryColumnList(tableName);
        IndexInfo indexInfo = new IndexInfo();
        indexInfo.setTableName(tableName);
        List<IndexInfo> indexList = mapper.baseQueryIndexList(indexInfo);

        Map<String, String> indexMap = new HashMap<>();
        if (indexList != null && indexList.size() > 0) {
            for (IndexInfo index : indexList) {
                indexMap.put(index.getColumnName(), index.getKeyName());
            }
        }

        List<TableColumnInfo> list = new ArrayList<>();

        for (ColumnInfo columnInfo : columnList) {
            TableColumnInfo tableInfo = new TableColumnInfo();
            if (indexMap.containsKey(columnInfo.getColumnName())) {
                tableInfo.setIndex(true);
            } else {
                tableInfo.setIndex(false);
            }
            //设置数据库字段名，用于Mapper中的查询语句
            tableInfo.setName(columnInfo.getColumnName());

            //字段名转换为驼峰命名格式，用于Java实体类字段
            tableInfo.setJavaName(StringUtils.lineToHump(tableInfo.getName()));

            tableInfo.setGetterName(StringUtils.lineToBigHump(tableInfo.getName()));

            //设置数据类型
            tableInfo.setType(columnInfo.getColumnType());

            //字段类型转换为Java的数据格式
            tableInfo.setJavaType(Mysql2JavaTypeCaster.getJavaType(tableInfo.getType()));

            //是否必填
            tableInfo.setRequired("NO".equals(columnInfo.getIsNullable()));

            tableInfo.setComment(columnInfo.getColumnComment());
            if ("PRI".equalsIgnoreCase(columnInfo.getColumnKey())) {
                tableInfo.setKey(true);
            }

            System.out.println(tableInfo);
            list.add(tableInfo);
        }
        return list;
    }


    public static void main(String[] args) {

        String name = "task_start_time";
        System.out.println(StringUtils.lineToHump(name));

        name = "Task";
        name = name.substring(0, 1).toLowerCase() + name.substring(1, name.length());
        System.out.println(name);
    }
}
